package cn.mini.mybatis.mybatis.builder.xml;

import cn.mini.mybatis.mybatis.builder.BaseBuilder;
import cn.mini.mybatis.mybatis.datasource.DataSourceFactory;
import cn.mini.mybatis.mybatis.io.Resources;
import cn.mini.mybatis.mybatis.mapping.Environment;
import cn.mini.mybatis.mybatis.session.Configuration;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.xml.sax.InputSource;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.Reader;
import java.util.List;
import java.util.Properties;

public class XMLConfigBuilder extends BaseBuilder {
    /**
     * 配置文件中的根节点即 configuration
     */
    private Element root;

    public XMLConfigBuilder(Reader reader) {
        // 1. 调用父类初始化Configuration
        super(new Configuration());
        // 2. dom4j 处理 xml
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(new InputSource(reader));
            root = document.getRootElement();
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    public Configuration parse() {
        parseConfiguration();
        return configuration;
    }


    /**
     * 解析 configurations下任意节点
     * 由于采用dom4j解析且维护配置文件根节点  configuration 节点下有很多子节点，所以这里使用递归的方式解析mappers内容
     */
    private void parseConfiguration() {
        environmentsElement(root.element("environments"));
        // 如果解析其他节点可在此直接添加对应方法进行解析
        mapperElement(root.element("mappers"));
    }

    /**
     * 解析 mappers 节点
     * @param mappers mappers 元素
     */
     private void mapperElement(Element mappers) {
        if (mappers != null) {
            List<Element> mapperElements = mappers.elements("mapper");
            for (Element mapperElement : mapperElements) {
                String resource = mapperElement.attributeValue("resource");
                String url = mapperElement.attributeValue("url");
                String mapperClass = mapperElement.attributeValue("class");
                if (resource != null && !resource.trim().isEmpty()) {
                    try (Reader reader = Resources.getResourceAsReader(resource)) {
                        XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(reader, resource, configuration);
                        xmlMapperBuilder.parse();
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                } else if (resource == null && url != null && !url.trim().isEmpty()) {
                    try (Reader reader = Resources.getResourceAsReader(url)) {
                        XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(reader, url, configuration);
                        xmlMapperBuilder.parse();
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                } else if (resource == null && url == null && mapperClass != null && !mapperClass.trim().isEmpty()) {
                    Class<?> mapperInterface;
                    try {
                        mapperInterface = Resources.classForName(mapperClass);
                        configuration.addMapper(mapperInterface);
                    } catch (ClassNotFoundException e) {
                        throw new RuntimeException(e);
                    }
                } else  {
                    throw new RuntimeException("A mapper element may only specify a url, resource or class, but not more than one.");
                }
            }
        }
     }


    /**
     *
     * 相关数据结构 暂时处理事务相关操作
     * <environments default="development">
     * <environment id="development">
     * <transactionManager type="JDBC">
     * <property name="..." value="..."/>
     * </transactionManager>
     * <dataSource type="POOLED">
     * <property name="driver" value="${driver}"/>
     * <property name="url" value="${url}"/>
     * <property name="username" value="${username}"/>
     * <property name="password" value="${password}"/>
     * </dataSource>
     * </environment>
     * </environments>
     */
    private void environmentsElement(Element context) {
        String environment = context.attributeValue("default");

        List<Element> environmentList = context.elements("environment");
        for (Element e : environmentList) {
            String id = e.attributeValue("id");
            if (environment.equals(id)) {
                // 数据源
                Element dataSourceElement = e.element("dataSource");
                DataSourceFactory dataSourceFactory = null;
                try {
                    dataSourceFactory = (DataSourceFactory) typeAliasRegistry
                            .resolveAlias(dataSourceElement.attributeValue("type"))
                            .newInstance();
                } catch (InstantiationException | IllegalAccessException ex) {
                    throw new RuntimeException(ex);
                }
                List<Element> propertyList = dataSourceElement.elements("property");
                Properties props = new Properties();
                // 构建一份配置文件信息
                for (Element property : propertyList) {
                    props.setProperty(property.attributeValue("name"),
                            property.attributeValue("value"));
                }
                dataSourceFactory.setProperties(props);
                DataSource dataSource = dataSourceFactory.getDataSource();

                // 构建环境
                Environment.Builder environmentBuilder = new Environment.Builder(id)
                        .dataSource(dataSource);
                configuration.setEnvironment(environmentBuilder.build());
            }
        }
    }

}
